/*
 *    Copyright (c) 2018-2025, lengleng All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the pig4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: lengleng (wangiegie@gmail.com)
 */
package com.pig4cloud.pigx.user.service.impl;

import cn.hutool.crypto.symmetric.AES;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.common.customize.enums.AbnormalEnum;
import com.pig4cloud.pigx.common.customize.exception.DuckweedException;
import com.pig4cloud.pigx.common.customize.security.utils.SecurityUtil;
import com.pig4cloud.pigx.common.customize.utils.id.IdWorker;
import com.pig4cloud.pigx.common.security.service.PigxUser;
import com.pig4cloud.pigx.user.constant.WalletConstant;
import com.pig4cloud.pigx.user.entity.Currency;
import com.pig4cloud.pigx.user.entity.User;
import com.pig4cloud.pigx.user.entity.UserAddress;
import com.pig4cloud.pigx.user.enums.UserEnums;
import com.pig4cloud.pigx.user.mapper.UserAddressMapper;
import com.pig4cloud.pigx.user.service.CurrencyService;
import com.pig4cloud.pigx.user.service.UserAddressService;
import com.pig4cloud.pigx.user.vo.AppUserAddressVO;
import lombok.AllArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.tron.trident.core.key.KeyPair;
import org.web3j.crypto.ECKeyPair;
import org.web3j.crypto.Keys;

import java.nio.charset.Charset;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.util.ArrayList;
import java.util.List;

/**
 *
 *
 * @author pigx code generator
 * @date 2022-11-21 11:33:15
 */
@Service
@AllArgsConstructor
public class UserAddressServiceImpl extends ServiceImpl<UserAddressMapper, UserAddress> implements UserAddressService {

	private final IdWorker idWorker;

	private final CurrencyService currencyService;

	@Override
	public R<List<AppUserAddressVO>> getAppUserAddress() {
		try {
			PigxUser user = SecurityUtil.getLoginUser();
			if (user == null) {
				throw new DuckweedException(AbnormalEnum.MSG.OPTIONS_USER_NOT_FOUND);
			}
			List<UserAddress> addresses = baseMapper.selectList(new QueryWrapper<UserAddress>() {{
				eq("user_id", user.getId());
			}});
			if (addresses.size() == 0) {
				throw new DuckweedException(AbnormalEnum.MSG.OPTIONS_USER_NOT_FOUND.getCode(),"未找到该用户的钱包地址");
			}
			int bscSize = (int) addresses.stream().filter(e -> e.getChain().equals(UserEnums.Chain.BSC.getValue())).count();
			if (bscSize == 0) {
				UserAddress userAddress = insertBscAddress(user.getId());
				addresses.add(userAddress);
			}
			int tronSize = (int) addresses.stream().filter(e -> e.getChain().equals(UserEnums.Chain.TRON.getValue())).count();
			if (tronSize == 0) {
				UserAddress userAddress = insertTronAddress(user.getId());
				addresses.add(userAddress);
			}
			// 获取币种信息
			List<AppUserAddressVO> voList = new ArrayList<>();
			for (UserAddress address : addresses) {
				AppUserAddressVO vo = new AppUserAddressVO();
				BeanUtils.copyProperties(address,vo);
				Currency currency = currencyService.getCurrency(WalletConstant.USDT,address.getChain());
				if (currency == null) {
					throw new DuckweedException(AbnormalEnum.MSG.BAD_SYMBOL.getCode(),"币种无效");
				}
				BeanUtils.copyProperties(currency,vo);
				vo.setCurrency(currency.getName());
				voList.add(vo);
			}
			return R.ok(voList);
		} catch (DuckweedException e) {
			throw e;
		} catch (Exception e) {
			throw new DuckweedException(AbnormalEnum.MSG.DISCONNECTED);
		}
	}

	/**
	 * 用户注册时新增波场链钱包地址
	 * @param user 用户
	 */
	@Override
	public void insertByRegistered(User user) {
		insertTronAddress(user.getId());
		insertBscAddress(user.getId());
	}

	public UserAddress insertTronAddress(Long userId) {
		Long count = baseMapper.selectCount(new QueryWrapper<UserAddress>() {{
			eq("user_id", userId);
			eq("chain",UserEnums.Chain.TRON.getValue());
		}});
		if (count > 0) {
			return null;
		}
		AES aes = new AES(WalletConstant.AES_KEY);
		// 账户（波场）
		KeyPair keyPair = KeyPair.generate();

		// String private key
		String tronPrivateKey = keyPair.toPrivateKey();

		// String public key
		String tronPublicKey = keyPair.toPublicKey();
		String tronAddress = keyPair.toBase58CheckAddress();
		// 加密
		String tronAesPrivateKey = aes.encryptBase64(tronPrivateKey, Charset.defaultCharset());
		UserAddress userAddress = new UserAddress();
		userAddress.setId(idWorker.nextId());
		// 用户id
		userAddress.setUserId(userId);
		// 地址
		userAddress.setAddress(tronAddress);
		// 私钥
		userAddress.setPrivateKey(tronAesPrivateKey);
		// 波场链
		userAddress.setChain(UserEnums.Chain.TRON.getValue());
		// 插入
		baseMapper.insert(userAddress);
		return userAddress;
	}

	public UserAddress insertBscAddress(Long userId) {
		Long count = baseMapper.selectCount(new QueryWrapper<UserAddress>() {{
			eq("user_id", userId);
			eq("chain",UserEnums.Chain.BSC.getValue());
		}});
		if (count > 0) {
			return null;
		}
		AES aes = new AES(WalletConstant.AES_KEY);
		// 账户 (bsc)
		ECKeyPair ecKeyPair;
		ecKeyPair = null;
		try {
			ecKeyPair = Keys.createEcKeyPair();
		} catch (InvalidAlgorithmParameterException | NoSuchAlgorithmException | NoSuchProviderException e) {
			throw new RuntimeException(e);
		}
		// 公钥
		String bscPublicKey = ecKeyPair.getPublicKey().toString(16);
		// 私钥
		String bscPrivateKey = ecKeyPair.getPrivateKey().toString(16);
		// 地址
		String bscAddress = "0x" + Keys.getAddress(bscPublicKey);
		// 加密
		String bscAesPrivateKey = aes.encryptBase64(bscPrivateKey, Charset.defaultCharset());
		UserAddress userAddress = new UserAddress() {{
			setId(idWorker.nextId());
			setUserId(userId);
			setAddress(bscAddress);
			setPrivateKey(bscAesPrivateKey);
			setChain(UserEnums.Chain.BSC.getValue());
		}};
		baseMapper.insert(userAddress);
		return userAddress;
	}

}
